#pragma once
#ifndef __G_MODULE_DESCRIPTOR_H__
#define __G_MODULE_DESCRIPTOR_H__

#include "GVersion.h"
#include "GModuleManager.h"
#include "../../Foundation/GUtilities/GLog.h"

namespace GEngine
{
	// These macro definitions with scopes does not scale well
	// Module related code should not use nested scope!
	//! Change these macros to pure c so there wont be any problems

	class GModule;

	class GModuleDescriptor
	{
	public:
									GModuleDescriptor(){}
									~GModuleDescriptor(){}

		virtual const char*			GetName() const = 0;
		virtual const char*			GetParent() const = 0;
		virtual const char*			GetImplemented() const = 0;
		virtual ::GEngine::GVersion	GetVersion() const = 0;
		virtual ::GEngine::GModule*	CreateInstance() const = 0;
	};

	// Module Definitions
	#define G_MODULE(ModuleName)\
	friend class ModuleName##Desc;\
	public:\
		static ::GEngine::GModuleDescriptor*	Descriptor();\
		virtual ::GEngine::GModuleDescriptor*	GetDescriptor();\
	private:
	
	// Module descriptor implementation
	#define G_MODULE_DESC(ModuleName, Parent, Implements)\
	class ModuleName##Desc : public ::GEngine::GModuleDescriptor\
	{\
	public:\
									ModuleName##Desc(){}\
									~ModuleName##Desc(){}\
		virtual const char*			GetName() const OVERRIDE {return #ModuleName;}\
		virtual const char*			GetParent() const OVERRIDE {return #Parent;}\
		virtual const char*			GetImplemented() const OVERRIDE {return #Implements;}\
		virtual ::GEngine::GVersion	GetVersion() const OVERRIDE {return ::GEngine::GVersion(0, 0, 0);}\
		virtual ::GEngine::GModule*	CreateInstance() const OVERRIDE {return new ModuleName();}\
	};\
	::GEngine::GModuleDescriptor* ModuleName::Descriptor()\
	{\
		static ModuleName##Desc StaticDesc;\
		return &StaticDesc;\
	}\
	::GEngine::GModuleDescriptor* ModuleName::GetDescriptor()\
	{\
		return ModuleName::Descriptor();\
	}\
	
	#ifdef G_DYNAMIC_MODULE
		// Dynamic module registration method
		#define G_MODULE_REGISTRATOR(ModuleName)\
		extern "C" G_MODULE_API void RegisterLibrary()\
		{\
			mGModuleManager->RegisterModule(ModuleName::Descriptor());\
		}
	#else
		// Static module registration method
		#define G_MODULE_REGISTRATOR(ModuleName)\
		class ModuleName##AutoRegistrator\
		{\
		public:\
			ModuleName##AutoRegistrator()\
			{\
				::mGModuleManager->RegisterModule(ModuleName::Descriptor());\
				::mGFileLogger->Log(G_LOG_TYPE_INFO, "%s registered.", ModuleName::Descriptor()->GetName());\
			}\
		} ModuleName##Registrator;
	#endif


	// ModuleName: Name of the module. Module will be registered with this name. e.g. GD3D11GraphicaModule, GDirectSoundModule
	// Parent: Name of the parent module. Should use the name of the module that this module is inherited from. e.g. GGraphicModule, GSoundModule
	// Implements: Name of the interface that this module actually implements. e.g. GGraphicModule, GSoundModule
	#define G_MODULE_DESCRIPTOR(ModuleName, Parent, Implements)\
	G_MODULE_DESC(ModuleName, Parent, Implements)\
	G_MODULE_REGISTRATOR(ModuleName)

}

#endif